home *** CD-ROM | disk | FTP | other *** search
- /*
- * $Id: gethostnamadr.c,v 1.7 1993/09/08 14:26:47 too Exp $
- *
- * Last modified: Wed Sep 8 16:50:00 1993 too
- *
- * HISTORY
- * $Log: gethostnamadr.c,v $
- * Revision 1.7 1993/09/08 14:26:47 too
- * Fixed getanswer (from gethostbyaddr) further. Now alias and addr lists
- * are NULL terminated. question is no longer copied. Removed that
- * unnecessary aligment by accident.
- *
- * Revision 1.6 1993/08/20 17:26:34 too
- * Fixed bug in getanswer that caused gethostbyaddr() to return
- * hostname w/ garpage at the end.
- * Added some comments w/ wponders
- * now answer buffer is aligned before host addresses are written.
- * this is unnecessary though.
- * getanswer still writes the question to the answer buffer. This will
- * be fixed later since it doesn't affect functionality
- *
- * Revision 1.5 1993/06/07 12:37:20 too
- * Changed inet_ntoa, netdatabase functions and WaitSelect() use
- * separate buffers for their dynamic buffers
- *
- * Revision 1.4 1993/06/04 11:16:15 jraja
- * Fixes for first public release.
- *
- * Revision 1.3 1993/06/03 20:22:24 too
- * Added variable usens. Fixed some bsd_free memory pointer arguments.
- * Fixed ptr aligment in makehostent
- *
- * Revision 1.2 1993/06/03 07:20:57 too
- * FIxed bugs with pointer arithmetic and destination addressess
- * and data lengths
- *
- * Revision 1.1 1993/06/01 16:35:59 too
- * Initial revision
- *
- *
- */
- /*
- * Copyright (c) 1985, 1988 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
- #if defined(LIBC_SCCS) && !defined(lint)
- static char sccsid[] = "@(#)gethostnamadr.c 6.45 (Berkeley) 2/24/91";
- #endif /* LIBC_SCCS and not lint */
-
- #include <sys/param.h>
- #include <sys/systm.h>
- #include <sys/socket.h>
- #include <sys/malloc.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- #include <ctype.h>
- #include <errno.h>
-
- #include <api/arpa_nameser.h>
- #include <api/resolv.h>
- #include <kern/amiga_includes.h>
- #include <api/amiga_api.h>
- #include <api/amiga_libcallentry.h>
- #include <api/amiga_raf.h>
- #include <api/allocdatabuffer.h>
- #include <kern/amiga_subr.h>
-
- #include <api/gethtbynamadr.h> /* prototypes (NO MORE BUGS HERE) */
-
- #define MAXALIASES 35
- #define MAXADDRS 35
-
- #if PACKETSZ > 1024
- #define MAXPACKET PACKETSZ
- #else
- #define MAXPACKET 1024
- #endif
-
- typedef union {
- HEADER hdr;
- u_char buf[MAXPACKET];
- } querybuf;
-
- typedef union {
- long al;
- char ac;
- } align;
-
- /*
- * macro for getting error value from another library base function
- * ( which is called directly here )
- */
-
- #define errno libPtr->errnoPtr[libPtr->errnoSize - 1]
-
- /*
- * hostent structure in SocketBase
- */
- #define HOSTENT ((struct hostent *)libPtr->hostents.db_Addr)
-
- /*
- * longword align given pointer (i.e. divides by 4)
- */
- #define ALIGN(p) (((u_int)(p) + (sizeof(long) - 1)) &~ (sizeof (long) -1))
-
- #define MAXALIASES 35
- #define MAXADDRS 35
-
- typedef char hostbuf_t[512];
-
- struct hoststruct {
- char * host_aliases[MAXALIASES + 1];
- char * h_addr_ptrs[MAXADDRS + 1];
- short host_alias_count;
- short h_addr_count;
- struct hostent host;
- hostbuf_t hostbuf;
- };
-
- static struct hostent * makehostent(struct SocketBase * libPtr,
- struct hoststruct * HS,
- char * ptr);
-
- extern int h_errno;
- LONG usens = 1;
-
- static char *
- getanswer(struct SocketBase * libPtr, querybuf *answer,int anslen, int iquery,
- struct hoststruct * HS)
- {
- register HEADER *hp;
- register u_char *cp; /* pointer to traverse in 'answer' */
- register int n;
- u_char *eom;
- int buflen = sizeof HS->hostbuf;
- char *bp; /* bp -- answer buffer pointer */
- int type, class, ancount, qdcount;
- int haveanswer, getclass = C_ANY;
- char **ap, **hap;
-
- eom = answer->buf + anslen;
- /*
- * find first satisfactory answer
- */
- hp = &answer->hdr;
- ancount = ntohs(hp->ancount); /* how many answers returned from nameserver */
- qdcount = ntohs(hp->qdcount); /* how many questions in nameserver query */
-
- /*
- * bp, points to start of buffer space where new resolved answer is to
- * be written. the bp is moved to next free space. Initially it is
- * set below, to start of buffer allocated for it-
- */
- bp = HS->hostbuf;
- /*
- * address cp to start of nameserver answers (after static sized header)
- */
- cp = answer->buf + sizeof(HEADER);
-
- /*
- * Any questions asked..hmm this should always be the case
- */
- if (qdcount) {
- #if 0 /* added by too 8.Sep.1993: skipping strange parts */
- /*
- * gethostbyaddr uses inverse query...
- */
- if (iquery) {
- if ((n = dn_expand((u_char *)answer->buf,
- (u_char *)eom, (u_char *)cp, (u_char *)bp,
- buflen)) < 0) {
- h_errno = NO_RECOVERY;
- return NULL;
- }
- cp += n + QFIXEDSZ;
- /*
- * Hostname in final hostent structure is written here in case
- * of gethostbyaddr. (from question section ???)
- */
- HS->host.h_name = bp;
- n = strlen(bp) + 1;
- bp += n;
- buflen -= n;
- }
- else
- #endif /* 0 */ /* 8Sep93: now code below skips all question strings */
- /*
- * here is normal query (gethostbyname). skipping query section
- * hmm, wondering why is it originally implemented as 2
- * __dn_skipname function calls ?
- */
- cp += __dn_skipname(cp, eom) + QFIXEDSZ;
- while (--qdcount > 0)
- cp += __dn_skipname(cp, eom) + QFIXEDSZ;
- }
- else if (iquery) {
- /*
- * no questions and inverse query :o
- */
- if (hp->aa)
- h_errno = HOST_NOT_FOUND;
- else
- h_errno = TRY_AGAIN;
- return NULL;
- }
- ap = HS->host_aliases;
- HS->host_alias_count = 1; /* there is always NULL as last pointer */
- hap = HS->h_addr_ptrs;
- HS->h_addr_count = 1; /* there is always NULL as last pointer */
-
- haveanswer = 0;
- while (--ancount >= 0 && cp < eom) {
- if ((n = dn_expand((u_char *)answer->buf, (u_char *)eom,
- (u_char *)cp, (u_char *)bp, buflen)) < 0)
- break;
- cp += n;
- /*
- * Type and class are type and class of answer in returned resource
- * record. see arpa[_/]nameserver.h for more information.
- */
- type = _getshort(cp);
- cp += sizeof(u_short);
- class = _getshort(cp);
- cp += sizeof(u_short) + sizeof(u_long);
- n = _getshort(cp);
- cp += sizeof(u_short);
-
- if (type == T_CNAME) { /* canonical name (add alias names)*/
- cp += n;
- if (HS->host_alias_count >= MAXALIASES)
- continue;
- *ap++ = bp;
- HS->host_alias_count++;
- n = strlen(bp) + 1;
- bp += n;
- buflen -= n;
- continue;
- }
- if (iquery && type == T_PTR) { /* domain name pointer (get domain
- name and return) */
- if ((n = dn_expand((u_char *)answer->buf,
- (u_char *)eom, (u_char *)cp, (u_char *)bp,
- buflen)) < 0) {
- cp += n;
- continue;
- }
- cp += n;
- HS->host.h_name = bp; /* well, rewrites name pointer if there were
- returned questions also... */
- haveanswer = 1;
- bp+= (strlen(bp) + 1);
- break;
- }
- if (iquery || type != T_A) {
- /*
- * here is strange answer from nameserver: inverse query should have
- * been handled earlyer and there should not be any other types
- * left than "host address"
- */
- #ifdef RES_DEBUG
- printf("unexpected answer type %d, size %d\n",
- type, n);
- #endif
- cp += n;
- continue;
- }
- if (haveanswer) {
- /*
- * Here if one host address answer is already returned (rather odd...)
- */
- if (n != HS->host.h_length) {
- cp += n;
- continue;
- }
- if (class != getclass) {
- cp += n;
- continue;
- }
- }
- else {
- /*
- * Fill in host address data and comparing info for next cycle (if any)
- */
- HS->host.h_length = n;
- getclass = class;
- HS->host.h_addrtype = (class == C_IN) ?
- AF_INET : AF_UNSPEC;
- if (!iquery) {
- /*
- * if not inverse query and haveanswer = 0 host name is first in
- * bp pointed buffer. (rather strange if answer already returned
- * and new addresses are to be added since aren't in that case
- * also names returned or is it inconsistent or have i missed
- * something ?
- */
- int n1;
-
- HS->host.h_name = bp;
- n1 = strlen(bp) + 1;
- bp += n1;
- buflen -= n1;
- }
- }
-
- /* bp = (char *)ALIGN(bp); /* align answer buffer for next host address */
-
- if (HS->host.h_length >= buflen) {
- #ifdef RES_DEBUG
- printf("size (%d) too big\n", host->h_length);
- #endif
- break;
- }
- /*
- * Fill next host address in address list
- */
- bcopy(cp, *hap++ = bp, n);
- HS->h_addr_count++;
- bp += n;
- buflen -= n;
- cp += n;
- haveanswer++;
- } /* while (--ancount ...) */
-
- if (haveanswer) {
- *ap = NULL;
- *hap = NULL;
- return bp;
- }
- else {
- h_errno = TRY_AGAIN;
- return NULL;
- }
- }
-
- struct hostent * SAVEDS RAF2 (_gethostbyname,
- struct SocketBase *, libPtr, a6,
- const char *, name, a0)
- #if 0
- {
- #endif
- querybuf *buf;
- int n;
- char * ptr;
- extern int inet_aton(const char *name, struct in_addr *ia);
- struct hoststruct * HS = NULL;
- struct hostent * anshost = NULL;
-
- CHECK_TASK2();
-
- /*
- * check if name consists only dots and digits.
- */
- if (isdigit(name[0])) {
- struct in_addr inaddr;
- u_long * lptr;
-
- if (!inet_aton(name, &inaddr)) {
- writeErrnoValue(libPtr, 0);
- return NULL;
- }
-
- if (allocDataBuffer(&libPtr->hostents,
- sizeof (struct hostent) + 28) == FALSE) {
- writeErrnoValue(libPtr, ENOMEM);
- return NULL;
- }
- HOSTENT->h_addrtype = AF_INET;
- HOSTENT->h_length = sizeof (struct in_addr);
- lptr = (u_long *)(HOSTENT + 1);
- *lptr++ = inaddr.s_addr;
- *(u_long **)(lptr) = lptr - 1;
- HOSTENT->h_addr_list = (char **)lptr;
- *++lptr = NULL;
- HOSTENT->h_aliases = (char **)lptr;
- HOSTENT->h_name = strcpy((char *)++lptr, name);
-
- return HOSTENT;
- }
- /*
- * Search local database (first) is usens not FIRST
- */
- if (usens != 1)
- if ((anshost =_gethtbyname(libPtr, name)) != NULL || usens == 0)
- return anshost;
- /*
- * Here if usens is FIRST or host not in local database and usens is SECOND
- */
- if ((HS = bsd_malloc(sizeof (querybuf) + sizeof (struct hoststruct),
- M_TEMP, M_WAITOK)) == NULL) {
- writeErrnoValue(libPtr, ENOMEM);
- return NULL;
- }
- buf = (querybuf *)(HS + 1);
-
- ObtainSemaphore(&res_lock);
- n = res_search(libPtr, name, C_IN, T_A, buf->buf, sizeof (querybuf));
- ReleaseSemaphore(&res_lock);
- if (n >= 0) {
- ptr = getanswer(libPtr, buf, n, 0, HS);
- if (ptr != NULL) {
- if ((anshost = makehostent(libPtr, HS, ptr)) != NULL) {
- anshost->h_addrtype = HS->host.h_addrtype;
- anshost->h_length = HS->host.h_length;
- }
- }
- }
- else {
- #ifdef RES_DEBUG
- printf("res_search failed\n");
- #endif
- /*
- * If usens is FIRST and host not found using resolver.
- */
- if (usens != 2)
- anshost =_gethtbyname(libPtr, name);
- }
- if (HS)
- bsd_free(HS, M_TEMP);
- return anshost;
-
- }
-
- struct hostent * SAVEDS RAF4 (_gethostbyaddr,
- struct SocketBase *, libPtr, a6,
- const char *, addr, a0,
- int, len, d0,
- int, type, d1)
- #if 0
- {
- #endif
- querybuf * buf;
- int n;
- char * ptr;
- struct hoststruct * HS = NULL;
- char * qbuf;
- struct hostent * anshost = NULL;
-
- CHECK_TASK2();
-
- if (type != AF_INET)
- return ((struct hostent *) NULL);
-
- /*
- * Search local database (first) is usens not FIRST
- */
- if (usens != 1)
- if ((anshost =_gethtbyaddr(libPtr, addr, len, type)) != NULL || usens == 0)
- return anshost;
-
- /*
- * Here if usens is FIRST or host not in local database and usens is SECOND
- */
- if ((HS = bsd_malloc(sizeof (querybuf) + MAXDNAME + 1 +
- sizeof (struct hoststruct), M_TEMP, M_WAITOK))
- == NULL) {
- writeErrnoValue(libPtr, ENOMEM);
- return NULL;
- }
- buf = (querybuf *)(HS + 1);
- qbuf = (caddr_t)(buf + 1);
-
- (void)sprintf(qbuf, "%lu.%lu.%lu.%lu.in-addr.arpa",
- ((unsigned)addr[3] & 0xff),
- ((unsigned)addr[2] & 0xff),
- ((unsigned)addr[1] & 0xff),
- ((unsigned)addr[0] & 0xff));
- ObtainSemaphore(&res_lock);
- n = res_query(libPtr, qbuf, C_IN, T_PTR, (char *)buf, sizeof (querybuf));
- ReleaseSemaphore(&res_lock);
-
- if (n >= 0) {
- ptr = getanswer(libPtr, buf, n, 1, HS);
- if (ptr != NULL) {
- if (HS->h_addr_count == 1) {
- HS->h_addr_count++;
- bcopy(addr, ptr, len);
- HS->h_addr_ptrs[0] = ptr;
- ptr += len;
- }
- else
- bcopy(addr, &HS->h_addr_ptrs[0], len);
- HS->h_addr_ptrs[1] = NULL;
- if ((anshost = makehostent(libPtr, HS, ptr)) != NULL) {
- anshost->h_addrtype = type;
- anshost->h_length = len;
- }
- }
- }
- else {
- #ifdef RES_DEBUG
- printf("res_query failed\n");
- #endif
- /*
- * If usens is FIRST and host not found using resolver.
- */
- if (usens != 2)
- anshost = _gethtbyaddr(libPtr, addr, len, type);
- }
- if (HS)
- bsd_free(HS, M_TEMP);
- return anshost;
- }
-
- static struct hostent * makehostent(struct SocketBase * libPtr,
- struct hoststruct * HS,
- char * ptr)
- {
- int n, i;
-
- i = (caddr_t)ALIGN(ptr) - (caddr_t)&HS->hostbuf;
- n = i + sizeof (struct hostent) + HS->h_addr_count * sizeof (char *) +
- HS->host_alias_count * sizeof (char *);
-
- if (allocDataBuffer(&libPtr->hostents, n) == FALSE) {
- writeErrnoValue(libPtr, ENOMEM);
- return NULL;
- }
- /*
- * copy ent data to user buffer (pointers will be set later)
- */
- bcopy(HS->hostbuf, (caddr_t)(HOSTENT + 1), i);
-
- /*
- * how much to add to old pointers
- */
- n = (caddr_t)HOSTENT + sizeof(struct hostent) - (caddr_t)&HS->hostbuf;
-
- /*
- * fill vital fields in user hostent structure
- */
- HOSTENT->h_name = HS->host.h_name + n;
-
- HOSTENT->h_aliases = (char **)((char *)(HOSTENT + 1) + i);
- for (i = 0; HS->host_aliases[i]; i++)
- HOSTENT->h_aliases[i] = HS->host_aliases[i] + n;
- HOSTENT->h_aliases[i++] = NULL;
-
- HOSTENT->h_addr_list = HOSTENT->h_aliases + i;
- for (i = 0; HS->h_addr_ptrs[i]; i++)
- HOSTENT->h_addr_list[i] = HS->h_addr_ptrs[i] + n;
- HOSTENT->h_addr_list[i] = NULL;
-
- return HOSTENT;
- }
-